package com.ophiux.common.log.event;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.ophiux.common.core.jackson.JavaTimeModule;
import com.ophiux.common.log.config.LogProperties;
import com.ophiux.system.api.feign.SysLogFeignApi;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;

import java.util.Objects;

/**
 * @desc: 异步监听日志事件  实现接口{@link InitializingBean}后，可以在初始化bean之前操作东西
 * @author: hhl
 * @date：2022/7/18 17:41
 */
@Slf4j
@RequiredArgsConstructor
public class SysLogListener implements InitializingBean {

    private final SysLogFeignApi sysLogFeignApi;

    // new 一个 避免日志脱敏策略影响全局ObjectMapper
    private final static ObjectMapper objectMapper = new ObjectMapper();

    private final LogProperties logProperties;

    @Async
    @Order
    @SneakyThrows
    @EventListener(SysLogEvent.class)
    public void saveSysLog(SysLogEvent event) {
        SysLogEventDTO source = (SysLogEventDTO) event.getSource();

        // json 格式刷参数放在异步中处理，提升性能
        if (Objects.nonNull(source.getBody()) && logProperties.isRequestEnabled()) {
            String params = objectMapper.writeValueAsString(source.getBody());
            source.setParams(StrUtil.subPre(params, logProperties.getMaxLength()));
        }
        sysLogFeignApi.saveLog(source);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        objectMapper.addMixIn(Object.class, PropertyFilterMixIn.class);
        String[] ignorableFieldNames = logProperties.getExcludeFields().toArray(new String[0]);

        FilterProvider filters = new SimpleFilterProvider().addFilter("filter properties by name", SimpleBeanPropertyFilter.serializeAllExcept(ignorableFieldNames));
        objectMapper.setFilterProvider(filters);
        objectMapper.registerModule(new JavaTimeModule());
    }

    @JsonFilter("filter properties by name")
    class PropertyFilterMixIn {

    }
}
